#include <assert.h>
#include <string>
#include <cstdlib>
#include <iostream>
#include <fstream>

#include "Bitmap.h"
#include "mapfile.h"

using namespace std;

int main(int argc, char *argv[])
{
        if (argc!=2) {
                printf("Usage: mapdeconv <map.smf>\n");
                printf("Version 0.1\n");
                return -1;
        }


		MapHeader header;
		MapTileHeader tileHeader;
		ifstream ifs;

		cout << "opening " << argv[1] << "\n";
		ifs.open(argv[1], ifstream::in | ifstream::binary);
		assert(ifs.good());
		ifs.read((char *) &header, sizeof(MapHeader));
		assert(strcmp(header.magic, "spring map file") == 0);
		assert(header.squareSize == 8);
		assert(header.texelPerSquare == 8);
		assert(header.tilesize == 32);

		cout << "square size: " << header.squareSize << "\n";
		cout << "texels per square: " << header.texelPerSquare << "\n";
		cout << "tile size: " << header.tilesize << "\n";

		if (header.version != 1) {
				cout << "SMF Version " << header.version << " is not supported.\n";
				return -1;
		}

		cout << "mapsize is " << header.mapx << " x " << header.mapy << "\n";

		ofstream ofs;

		ifs.seekg(header.heightmapPtr, ios::beg);
		ofs.open("heightmap16bit.raw", ofstream::out | ofstream::binary);
		for (int i = 0; i < (header.mapx + 1) * (header.mapy + 1); i++) {
				unsigned short h;
				ifs.read((char *) &h, sizeof(unsigned short));
				ofs.write((char *) &h, sizeof(unsigned short));
		}
		ofs.close();

        ifs.seekg(header.metalmapPtr, ios::beg);
        int size = (header.mapx/2)*(header.mapy/2);
        unsigned char *buf = new unsigned char[size];
        ifs.read((char*)buf, size);
        unsigned char *metalbuf = new unsigned char[size * 4];
        CBitmap metal(metalbuf, header.mapx/2, header.mapy/2);
        for(int y=0;y<metal.ysize;++y) {
            for(int x=0;x<metal.xsize;++x) {
                metal.mem[(y*metal.xsize+x)*4+0] = buf[y*metal.xsize+x];
                //printf("%d ",buf[y*metal.xsize+x]);
            }
        }
        metal.Save("metalmap.bmp");
        delete [] metalbuf;
        delete [] buf;

		ifs.seekg(header.tilesPtr, ios::beg);
		ifs.read((char *) &tileHeader, sizeof(MapTileHeader));
		cout << tileHeader.numTileFiles << " tile files, " << tileHeader.
				numTiles << " tiles total.\n";

		int tileIndex = 0;
		unsigned char *tiles =
				new unsigned char[tileHeader.numTiles * SMALL_TILE_SIZE];
		for (int tf = 0; tf < tileHeader.numTileFiles; tf++) {
				unsigned long ntiles = 0;
				char tilefile[255];
				ifs.read((char *) &ntiles, sizeof(unsigned long));
				ifs.getline(tilefile, 255, '\0');
				cout << tilefile << ": " << ntiles << " tiles.\n";

				TileFileHeader tileFileHeader;
				ifstream itf;
				itf.open(tilefile, ifstream::in | ifstream::binary);
				assert(itf.good());
				itf.read((char *) &tileFileHeader, sizeof(TileFileHeader));
				assert(strcmp(tileFileHeader.magic, "spring tilefile") == 0);
				if (tileFileHeader.version != 1) {
						cout << "SMT version " << tileFileHeader.
								version << " is not supported.\n";
						return -1;
				}
				cout << "Reading " << tileFileHeader.numTiles << " tiles...";
				cout << SMALL_TILE_SIZE *
						tileFileHeader.
						numTiles << " bytes. " << sizeof(TileFileHeader) << "\n";
				itf.read((char *) tiles + tileIndex,
								 SMALL_TILE_SIZE * tileFileHeader.numTiles);
				itf.close();
				tileIndex += (SMALL_TILE_SIZE * tileFileHeader.numTiles);
		}

		int tilex = (header.mapx * header.texelPerSquare / header.tilesize);
		int tiley = (header.mapy * header.texelPerSquare / header.tilesize);

		int sz = tilex * tiley;
		cout << tilex << " x " << tiley << " = " << sz << " Tiles.\n";
		int *tindex = new int[sz];
		ifs.read((char *) tindex, sizeof(int) * sz);

		//*  Texture.bmp (mapsize*64*8 pixels)
		//* Height.bmp (mapsizesize*8+1 pixels)
		//* Metal.bmp (mapsize*8+1 pixels)
		//* Feature.bmp (mapsize*8 pixels)

		unsigned long mem =
				((tilex * header.tilesize) * (tiley * header.tilesize)) * 4;
		cout << "Memory required: " << mem << "\n";
		unsigned char *data = new unsigned char[mem];

		//xsize=bigTex.xsize/8;
		//ysize=bigTex.ysize/8;
		//int tilex=xsize/4;
		//int tiley=ysize/4;
		for (int a = 0; a < tiley; a++) {
				cout << (a * 100) / (tiley) << "% ";
				for (int b = 0; b < tilex; b++) {

						int t = tindex[(a * tilex) + b];

						//cout << a << "," << b << " ";
						CBitmap tile32;
						tile32.CreateFromDXT1((unsigned char *)&tiles[t * SMALL_TILE_SIZE],
															 header.tilesize, header.tilesize);

						assert(tile32.xsize == header.tilesize);
						assert(tile32.ysize == header.tilesize);

                        unsigned long starty = a*header.tilesize;
                        unsigned long startx = b*header.tilesize;

                        int height=tile32.ysize;
                        int width=tile32.xsize;
                        int xsize = tilex*header.tilesize;
                        for(int y=0;y<height;++y){
                            for(int x=0;x<width;++x){
                                data[((starty+y)*xsize+startx+x)*4]=tile32.mem[(y*width+x)*4];
                                data[((starty+y)*xsize+startx+x)*4+1]=tile32.mem[(y*width+x)*4+1];
                                data[((starty+y)*xsize+startx+x)*4+2]=tile32.mem[(y*width+x)*4+2];
                                data[((starty+y)*xsize+startx+x)*4+3]=tile32.mem[(y*width+x)*4+3];
                            }
                        }
				}
		}
		delete[]tindex;
		delete[]tiles;

		cout << "\n";
		cout << "Saving texture\n";
		CBitmap bmp(data, tilex * header.tilesize, tiley * header.tilesize);
		bmp.Save("texture.bmp");
		delete [] data;

		ifs.close();
		cout << "Finished.\n";
		return 0;
}
